const { DataTypes, Model } = require("sequelize");
const dayjs = require("dayjs");
const { isEmpty, makePassword, checkPassword } = require("./utils");

const DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";

const toPlain = (obj, exclude = []) => {
  let rs = {};
  Object.entries(obj).forEach(([key, val]) => {
    if (!exclude.includes(key)) rs[key] = val;
  });
  return rs;
};

class BaseModel extends Model {
  toPlain(exclude) {
    exclude = isEmpty(exclude) ? this.constructor.exclude : exclude;
    return toPlain(this.dataValues, exclude);
  }
}
class User extends BaseModel {
  static exclude = ["password", "active", "superuser"];
  /**
   * 验证密码
   *
   * @param {string} password
   * @returns {boolean}
   */
  checkPassword(password) {
    return checkPassword(password, this.password);
  }
}

class Todo extends BaseModel {}

const initModels = (sequelize) => {
  User.init(
    {
      id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
      username: { type: DataTypes.STRING(20), allowNull: false },
      password: {
        type: DataTypes.STRING(128),
        allowNull: false,
        set(val) {
          // 加密密码
          this.setDataValue("password", makePassword(val));
        },
      },
      nickname: { type: DataTypes.STRING(50) },
      active: { type: DataTypes.BOOLEAN, defaultValue: true },
      superuser: { type: DataTypes.BOOLEAN, defaultValue: false },
      avatar: { type: DataTypes.STRING },
      updated_at: {
        type: DataTypes.DATE,
        defaultValue: sequelize.literal("current_timestamp"),
      },
      created_at: {
        type: DataTypes.DATE,
        defaultValue: sequelize.literal("current_timestamp"),
      },
    },
    {
      sequelize,
      modelName: "User",
      indexes: [{ unique: true, fields: ["username"] }],
    }
  );

  Todo.init(
    {
      id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
      title: { type: DataTypes.STRING(100), allowNull: false },
      description: { type: DataTypes.STRING(1000), allowNull: false },
      priority: {
        type: DataTypes.ENUM,
        values: ["normal", "important", "crucial"],
        allowNull: false,
      },
      finished_at: {
        type: DataTypes.DATE,
        set(val) {
          this.setDataValue(
            "finished_at",
            val ? dayjs(val).format(DATETIME_FORMAT) : null
          );
        },
      },
      created_at: {
        type: DataTypes.DATE,
        defaultValue: sequelize.literal("CURRENT_TIMESTAMP"),
      },
    },
    {
      sequelize,
      modelName: "Todo",
    }
  );

  User.hasMany(Todo);
  Todo.belongsTo(User, { foreignKey: { allowNull: false } });
};

module.exports = {
  DATETIME_FORMAT,
  initModels,
  User,
  Todo,
};
